
package com.dongqi.utils;


import lombok.extern.slf4j.Slf4j;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.filter.ElementFilter;
import org.jdom.filter.Filter;
import org.jdom.input.DOMBuilder;
import org.jdom.output.XMLOutputter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/**
 * XML解析器封装接口
 * @version Date: 2004-11-6
 * @author gr shi
 */
@Slf4j
public class XmlParser {


	public static final String SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
	public static final String XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
	public static final String SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";

	private DocumentBuilderFactory getDocumentBuilderFactory() {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		return factory;
	}




	/**
	 * @param msgStr 输入得String
	 * @return
	 * @throws Exception
	 * @see Document parser(InputStream in) throws Exception
	 */
	public Document parser(String msgStr) throws Exception {
		ByteArrayInputStream bin = new ByteArrayInputStream(msgStr.getBytes());
		return parser(bin);
	}

	/**
	 * @param file
	 * @return
	 * @throws Exception
	 * @see Document parser(InputStream in) throws Exception
	 */
	public Document parser(File file) throws Exception {
		FileInputStream fin = new FileInputStream(file);
		return parser(fin);
	}

	/**
	 * @param doc
	 * @param file
	 * @throws Exception
	 */
	public void transform(Document doc, File file) throws Exception {
		FileOutputStream fout = new FileOutputStream(file);
		transform(doc, fout);
	}

	/**
	 * @param doc
	 * @param file
	 * @param encoding
	 * @throws Exception
	 */
	public void transform(Document doc, File file, String encoding) throws Exception {
		FileOutputStream fout = new FileOutputStream(file);
		transform(doc, fout, encoding);
	}

	public XmlParser() {
	}

	/**
	 * 通过file生成Document对象，使用DOM方式，parser时不校验
	 * @param in XML的输入流
	 * @return 返回生成的Document
	 * @throws Exception
	 */
	public Document parser(InputStream in) throws Exception {
		DocumentBuilderFactory factory = getDocumentBuilderFactory();
		DocumentBuilder parser = factory.newDocumentBuilder();
		DOMBuilder jdomBuild = new DOMBuilder();
		return preModify(jdomBuild.build(parser.parse(in)));
	}

	/**
	 * 把xml的Document输出到文件，使用DOM方式 默认的xml的编码为UTF-8
	 * @param doc Document对象
	 * @param out Document对象的输出流
	 * @throws Exception transform运行时出错，抛出异常
	 */
	public void transform(Document doc, OutputStream out) throws Exception {
		transform(doc, out, "UTF-8");
	}

	/**
	 * 把xml的Document输出到文件，使用DOM方式
	 * @param doc Document对象
	 * @param out Document对象的输出流
	 * @param encoding xml的输出编码
	 * @throws Exception transform运行时出错，抛出异常
	 */
	public void transform(Document doc, OutputStream out, String encoding) throws Exception {
	/*	DOMSource ds = new DOMSource(doc);
		StreamResult sr = new StreamResult(out);
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer t = tf.newTransformer();
		t.setOutputProperty(OutputKeys.ENCODING, encoding);
		t.transform(ds, sr);
	*/
	    XMLOutputter outp = new XMLOutputter();

        outp.output(doc, out);
	}

	/**
	 * 取文件
	 * @param fileName 文件名，以classpath为根路径
	 * @return 文件的InputStream
	 */
	public static InputStream getResource(String fileName) {
		return XmlParser.class.getClassLoader().getResourceAsStream(fileName);
	}

	/**
	 * 预先处理，判断并修改trade_type和hs_code
	 * @param document 预解析的org.jdom.docuement对象
	 */
	private Document preModify(Document document) {
		//select all trade_type whose length is greater than 2
		List tradeTypeList = new ArrayList();
		Filter tradeTypeFilter = new ElementFilter("Trade_Type");
		Element root = document.getRootElement();
		Iterator iterator = root.getDescendants(tradeTypeFilter);
		while (iterator.hasNext()) {
			Element tradeType = (Element) iterator.next();
			if (tradeType.getTextTrim().length() > 2) {
				tradeTypeList.add(tradeType);
			}
		}
		//modify the trade type nodes
		for(int i = 0; i < tradeTypeList.size(); i++) {
			Element e = (Element) tradeTypeList.get(i);
			log.debug("****Modify the Trade_Type Element " + e);
			e.setText("99");
		}

		//select all wrong or empty HS code
		List emptyNodeList = new ArrayList();
		List errorNodeList = new ArrayList();
		Filter hsFilter = new ElementFilter("Goods_HS");
		Iterator it = root.getDescendants(hsFilter);
		while (it.hasNext()) {
			Element hs = (Element) it.next();
			String value = hs.getTextTrim();
			if ("".equals(value)) {
				emptyNodeList.add(hs);
			} else if (!value.matches("[0-9]{8}|[0-9]{10}")) {
				errorNodeList.add(hs);
			}
		}
		//modify the hs codes
		for(int i = 0; i < emptyNodeList.size(); i++) {
			Element hs = (Element) emptyNodeList.get(i);
			log.debug("****Modify the empty Goods_HS Element " + hs);
			hs.setText("9999999999");
		}
		for(int i = 0; i < errorNodeList.size(); i++) {
			Element hs = (Element) errorNodeList.get(i);
			log.debug("****Modify the error Goods_HS Element " + hs);
			hs.setText("9999999998");
		}

		List emptyMainHS = new ArrayList();
		List errorMainHs = new ArrayList();
		Filter mainHsFilter = new ElementFilter("Main_Goods_HS");
		Iterator itr = root.getDescendants(mainHsFilter);
		while (itr.hasNext()) {
			Element mainHs = (Element) itr.next();
			String s = mainHs.getTextTrim();
			if ("".equals(s)) {
				emptyMainHS.add(mainHs);
			} else if (!s.matches("[0-9]{8}|[0-9]{10}")) {
				errorMainHs.add(mainHs);
			}
		}
		for(int i = 0; i < emptyMainHS.size(); i++) {
			Element mainHs = (Element) emptyMainHS.get(i);
			log.debug("****Modify the empty Main_Goods_HS Element " + mainHs);
			mainHs.setText("9999999999");
		}
		for(int i = 0; i < errorMainHs.size(); i++) {
			Element mainHs = (Element) errorMainHs.get(i);
			log.debug("****Modify the error Main_Goods_HS Element " + mainHs);
			mainHs.setText("9999999998");
		}

		return document;
	}

}
